home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 2004 #11
/
Amiga Plus CD - 2004 - No. 11.iso
/
AmiSoft
/
Util
/
conv
/
Acvt.lha
/
Acvt 1.07
/
sources
/
cdsk_dcm.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1999-06-10
|
15KB
|
763 lines
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "cdsk_dcm.h"
#include "cfile.h"
#include "cprefile.h"
#include "autil.h"
//#define _DCM_DUMP_
#define DCM_CHANGE_BEGIN 0x41 //Change only start of sector
#define DCM_DOS_SECTOR 0x42 //128 byte compressed sector
#define DCM_COMPRESSED 0x43 //Uncompressed/compressed pairs
#define DCM_CHANGE_END 0x44 //Change only end of sector
#define DCM_PASS_END 0x45 //End of pass
#define DCM_SAME_AS_BEFORE 0x46 //Same as previous non-zero
#define DCM_UNCOMPRESSED 0x47 //Uncompressed sector
#define DCM_HEADER_SINGLE 0xFA
#define DCM_HEADER_MULTI 0xF9
#define DCM_DENSITY_SD 0 //Single density, 90K
#define DCM_DENSITY_DD 1 //Double density, 180K
#define DCM_DENSITY_ED 2 //Enhanced density, 130K
CDcm::CDcm() : CDisk()
{
#ifdef _MEMORY_DUMP_
printf( "CDcm constructed: %08X\n", this );
#endif
}
CDcm::~CDcm()
{
#ifdef _MEMORY_DUMP_
printf( "CDcm destructed: %08X\n", this );
#endif
}
BOOL CDcm::Load( char* szFname, BOOL, BOOL )
{
BYTE btArcType = 0; //Block type for first block
BYTE btBlkType; //Current block type
m_bAlreadyFormatted = FALSE;
m_bLastPass = FALSE;
m_wCurrentSector = 0;
CFile cfo;
CPreFile cf;
if ( !cfo.Open( szFname ) )
{
sprintf( m_szLastError, "DCM: Can't open '%s'", szFname );
m_iErrorCode = CDISK_ERROR_CANT_OPEN;
return FALSE;
}
strcpy( m_szFname, szFname );
cf.Open( &cfo, 20 );
m_lFileLength = cf.GetLength();
for(;;) //outpass
{
if ( cf.Tell() >= m_lFileLength )
{
if ( ( !m_bLastPass ) && ( btArcType == DCM_HEADER_MULTI ) )
{
sprintf( m_szLastError,"DCM: Multi-part archive error.\n" \
"To process these files, you must first combine the files into a single file." );
m_iErrorCode = CDCM_FORMAT_VIOLATED;
return FALSE;
}
}
btArcType = cf.readb();
switch( btArcType )
{
case DCM_HEADER_MULTI:
case DCM_HEADER_SINGLE:
if ( !DecodeRecFA( cf ) )
return FALSE;
break;
default:
sprintf( m_szLastError, "DCM: %02X is an unknown header block.\n", btArcType );
return FALSE;
}
for(;;) //inpass
{
btBlkType = cf.readb();
if ( btBlkType == DCM_PASS_END )
break;
if ( cf.Tell() >= m_lFileLength )
{
sprintf( m_szLastError, "DCM: EOF before end block." );
m_iErrorCode = CDCM_FORMAT_VIOLATED;
return FALSE;
}
BOOL bRes = TRUE;
*m_szLastError = '\0';
switch( btBlkType & 0x7F )
{
case DCM_CHANGE_BEGIN:
bRes = DecodeRec41( cf );
break;
case DCM_DOS_SECTOR:
bRes = DecodeRec42( cf );
break;
case DCM_COMPRESSED:
bRes = DecodeRec43( cf );
break;
case DCM_CHANGE_END:
bRes = DecodeRec44( cf );
break;
case DCM_SAME_AS_BEFORE:
//not needed
//bRes = DecodeRec46( cf );
break;
case DCM_UNCOMPRESSED:
bRes = DecodeRec47( cf );
break;
default:
{
switch( btBlkType )
{
case DCM_HEADER_MULTI:
case DCM_HEADER_SINGLE:
sprintf( m_szLastError, "DCM: Trying to start section but last section never had "
"an end section block.");
break;
default:
sprintf( m_szLastError, "DCM: %02X is an unknown block type. File may be "
"corrupt.",btBlkType);
break;
}
m_iErrorCode = CDCM_FORMAT_VIOLATED;
return FALSE;
}
}
if ( !bRes )
{
sprintf( m_szLastError, "DCM: Block %02X decode error!", btBlkType );
m_iErrorCode = CDCM_FORMAT_VIOLATED;
return FALSE;
}
if ( !WriteSector( m_wCurrentSector, m_abtCurrBuff ) )
return FALSE;
if ( btBlkType & 0x80 )
m_wCurrentSector++;
else
m_wCurrentSector = cf.readLEw();
} //infinite for (inpass)
//End block
if ( m_bLastPass )
break;
} //infinite for (outpass)
cf.Close();
cfo.Close();
return TRUE;
}
BOOL CDcm::DecodeRec41( CGenFile& cf )
{
#ifdef _DCM_DUMP_
printf( "dec41: %08lX\n", cf.Tell() - 1 );
#endif
int iOffset = cf.readb();
BYTE* pbt = m_abtCurrBuff + iOffset;
do
{
*( pbt-- ) = cf.readb();
} while( iOffset-- );
return TRUE;
}
BOOL CDcm::DecodeRec42( CGenFile& cf )
{
#ifdef _DCM_DUMP_
printf( "dec42: %08lX\n", cf.Tell() - 1 );
#endif
sprintf( m_szLastError, "DCM: Record type 0x42 untested. Uncomment?" );
return FALSE;
//TODO: uncomment later!
//cf.Read( m_abtCurrBuff + 123, 5 );
//memset( m_abtCurrBuff, m_abtCurrBuff[ 123 ], 123 );
//return TRUE;
}
BOOL CDcm::DecodeRec43( CGenFile& cf )
{
#ifdef _DCM_DUMP_
printf( "dec43: %08lX\n", cf.Tell() - 1 );
#endif
BYTE* pbtP = m_abtCurrBuff;
BYTE* pbtE;
BYTE* pbtEnd = m_abtCurrBuff + m_iSectorSize;
do
{
//uncompressed string
if ( pbtP != m_abtCurrBuff )
pbtE = m_abtCurrBuff + ReadOffset( cf );
else
pbtE = m_abtCurrBuff + cf.readb();
if ( pbtE < pbtP )
return FALSE;
#ifdef _DCM_DUMP_
printf( "dec43: uncst: %p %p %ld\n", pbtP, pbtE, pbtE - pbtP );
#endif
if ( pbtE != pbtP )
{
cf.Read( pbtP, pbtE - pbtP );
pbtP = pbtE;
}
if ( pbtP >= pbtEnd )
break;
//rle compressed string
pbtE = m_abtCurrBuff + ReadOffset( cf );
BYTE c = cf.readb();
#ifdef _DCM_DUMP_
printf( "dec43: cst: %p %p %ld\n", pbtP, pbtE, pbtE - pbtP );
#endif
if ( pbtE < pbtP )
return FALSE;
memset( pbtP, c, pbtE - pbtP );
pbtP = pbtE;
} while( pbtP < pbtEnd );
return TRUE;
}
BOOL CDcm::DecodeRec44( CGenFile& cf )
{
#ifdef _DCM_DUMP_
printf( "dec44: %08lX\n", cf.Tell() - 1 );
#endif
int iOffset = ReadOffset( cf );
cf.Read( m_abtCurrBuff + iOffset, m_iSectorSize - iOffset );
return TRUE;
}
BOOL CDcm::DecodeRec46( CGenFile& cf )
{
#ifdef _DCM_DUMP_
printf( "dec46: %08lX\n", cf.Tell() - 1 );
#endif
return TRUE;
}
BOOL CDcm::DecodeRec47( CGenFile& cf )
{
#ifdef _DCM_DUMP_
printf( "dec47: %08lX\n", cf.Tell() - 1 );
#endif
//TODO: Is this TRUE or NOT???
//cf.Read( m_abtCurrBuff, ( m_wCurrentSector < 4 ? 128 : m_iSectorSize ) );
cf.Read( m_abtCurrBuff, m_iSectorSize );
return TRUE;
}
BOOL CDcm::DecodeRecFA( CGenFile& cf )
{
#ifdef _DCM_DUMP_
printf( "decFA: %08lX\n", cf.Tell() - 1 );
#endif
BYTE btPom = cf.readb();
BYTE btDensity = ( btPom >> 5 ) & 0x03;
//BYTE btPass = btPom & 0x1F;
m_bLastPass = ( btPom & 0x80 ) ? TRUE : FALSE;
int iSpT;
int iTracks;
switch( btDensity )
{
case DCM_DENSITY_SD:
iTracks = 40;
iSpT = 18;
m_iSectorSize = 128;
break;
case DCM_DENSITY_DD:
iTracks = 40;
iSpT = 18;
m_iSectorSize = 256;
break;
case DCM_DENSITY_ED:
iTracks = 40;
iSpT = 26;
m_iSectorSize = 128;
break;
default:
sprintf( m_szLastError,"DCM: Density type unknown (%02X)\n", btDensity );
return FALSE;
}
if ( !m_bAlreadyFormatted )
{
DISK_GEOMETRY dg;
dg.iSides = 1;
dg.iTracks = iTracks;
dg.iSectorsPerTrack = iSpT;
dg.iBytesPerSector = m_iSectorSize;
if ( !Format( &dg ) )
return FALSE;
m_bAlreadyFormatted = TRUE;
}
m_wCurrentSector = cf.readLEw();
return TRUE;
}
WORD CDcm::ReadOffset( CGenFile& cf )
{
BYTE bt = cf.readb();
return( bt ? bt : 256 );
}
#ifdef __CDISK_WRITE__
BOOL CDcm::Save( char* szOutFile, BOOL bOverWrite )
{
if ( !bOverWrite && !access( szOutFile, F_OK ) )
{
sprintf( m_szLastError, "DCM: File already exists! '%s'", szOutFile );
return FALSE;
}
int iDensity = -1;
m_iSectorSize = m_geometry.iBytesPerSector;
if ( m_iSectorSize == 0x80 )
{
if ( m_geometry.iTracks == 40 )
{
if ( m_geometry.iSectorsPerTrack == 18 )
iDensity = DCM_DENSITY_SD;
if ( m_geometry.iSectorsPerTrack == 26 )
iDensity = DCM_DENSITY_ED;
}
}
if ( m_iSectorSize == 0x100 )
{
if ( ( m_geometry.iSectorsPerTrack == 18 ) &&
( m_geometry.iTracks == 40 ) )
iDensity = DCM_DENSITY_DD;
}
if ( iDensity == - 1 )
{
sprintf( m_szLastError, "DCM: Can't work with such density!" );
return FALSE;
}
int iPass = 1;
m_pbtPass = new BYTE [ 0x6500 ];
CFile cf;
if ( !cf.Create( szOutFile ) )
{
sprintf( m_szLastError, "DCM: Can't create '%s'", szOutFile );
delete [] m_pbtPass;
return FALSE;
}
int iFirstSector = 0;
int iPrevSector = 0;
int iCurrentSector = 1;
memset( m_abtPrevBuff, 0, m_iSectorSize );
EncodeRecFA( FALSE, iPass, iDensity, iFirstSector );
//here should be other compression
while( iCurrentSector <= m_geometry.iSectors )
{
iFirstSector = 0;
while( ( m_pbtCurr - m_pbtPass ) < 0x5EFD )
{
if ( iCurrentSector > m_geometry.iSectors )
break;
ReadSector( m_abtCurrBuff, iCurrentSector );
BOOL bSkip = IsBlockEmpty( m_abtCurrBuff, m_iSectorSize );
//first non empty sector is marked as first, what a surprise! :)
if ( !bSkip && !iFirstSector )
{
iFirstSector = iCurrentSector;
iPrevSector = iCurrentSector;
}
//if just skipped, increment sector
if ( bSkip )
{
iCurrentSector++;
}
else
{
//if there is a gap, write sector number
if ( ( iCurrentSector - iPrevSector ) > 1 )
{
*( m_pbtCurr++ ) = iCurrentSector;
*( m_pbtCurr++ ) = iCurrentSector >> 8;
}
else
{
//else mark previous record
*m_pbtLastRec |= 0x80;
}
//first sector could be encoded with only some data
if ( iCurrentSector == iFirstSector )
EncodeRec( TRUE );
else
{
//if are same, encode as record 46
if ( !memcmp( m_abtPrevBuff, m_abtCurrBuff, m_iSectorSize ) )
EncodeRec46();
else
EncodeRec( FALSE );
}
//store this sector as previous
memcpy( m_abtPrevBuff, m_abtCurrBuff, m_iSectorSize );
//and move pointers
iPrevSector = iCurrentSector;
iCurrentSector++;
}
}
//mark previous sector
*m_pbtLastRec |= 0x80;
//encode end
EncodeRec45();
BYTE* pEnd = m_pbtCurr;
//change beginning block
if ( iCurrentSector > m_geometry.iSectors )
EncodeRecFA( TRUE, iPass, iDensity, iFirstSector );
else
EncodeRecFA( FALSE, iPass, iDensity, iFirstSector );
//and write whole pass
if ( ( pEnd - m_pbtPass ) > 0x6000 )
{
sprintf( m_szLastError, "DCM: Internal error! Pass too long!" );
delete [] m_pbtPass;
cf.Close();
unlink( szOutFile );
return FALSE;
}
if ( !cf.Write( m_pbtPass, pEnd - m_pbtPass ) )
{
sprintf( m_szLastError, "DCM: Can't write!" );
delete [] m_pbtPass;
cf.Close();
unlink( szOutFile );
return FALSE;
}
iPass++;
}
cf.Close();
delete [] m_pbtPass;
return TRUE;
}
void CDcm::EncodeRecFA( BOOL bLast, int iPass, int iDensity, int iFirstSec )
{
m_pbtCurr = m_pbtPass;
#ifdef _DCM_DUMP_
printf( "ERFA: %08lX\n", m_pbtCurr - m_pbtPass );
#endif
m_pbtLastRec = m_pbtCurr;
BYTE btType = bLast ? 0x80 : 0;
btType |= ( iDensity & 3 ) << 5;
btType |= ( iPass & 0x1F );
*( m_pbtCurr++ ) = DCM_HEADER_SINGLE;
*( m_pbtCurr++ ) = btType;
*( m_pbtCurr++ ) = iFirstSec;
*( m_pbtCurr++ ) = iFirstSec >> 8;
}
void CDcm::EncodeRec45()
{
#ifdef _DCM_DUMP_
printf( "ER45: %08lX\n", m_pbtCurr - m_pbtPass );
#endif
m_pbtLastRec = m_pbtCurr;
*( m_pbtCurr++ ) = DCM_PASS_END;
}
void CDcm::EncodeRec46()
{
#ifdef _DCM_DUMP_
printf( "ER46: %08lX\n", m_pbtCurr - m_pbtPass );
#endif
m_pbtLastRec = m_pbtCurr;
*( m_pbtCurr++ ) = DCM_SAME_AS_BEFORE;
}
void CDcm::EncodeRec( BOOL bIsFirstSector )
{
#ifdef _DCM_DUMP_
printf( "ER: %08lX\n", m_pbtCurr - m_pbtPass );
#endif
m_pbtLastRec = m_pbtCurr;
BYTE abtBuff41[ 0x300 ];
BYTE abtBuff43[ 0x300 ];
BYTE abtBuff44[ 0x300 ];
BYTE* abtBuff47 = m_abtCurrBuff;
int iEnd41 = 0x300;
int iEnd43 = 0x300;
int iEnd44 = 0x300;
int iBestMethod = DCM_UNCOMPRESSED;
int iBestEnd = m_iSectorSize;
BYTE* pbtBest = abtBuff47;
EncodeRec43( abtBuff43, &iEnd43, m_abtCurrBuff, m_iSectorSize );
if ( !bIsFirstSector )
{
EncodeRec41( abtBuff41, &iEnd41, m_abtCurrBuff, m_abtPrevBuff, m_iSectorSize );
EncodeRec44( abtBuff44, &iEnd44, m_abtCurrBuff, m_abtPrevBuff, m_iSectorSize );
}
if ( iEnd41 < iBestEnd )
{
iBestMethod = DCM_CHANGE_BEGIN;
iBestEnd = iEnd41;
pbtBest = abtBuff41;
}
if ( iEnd43 < iBestEnd )
{
iBestMethod = DCM_COMPRESSED;
iBestEnd = iEnd43;
pbtBest = abtBuff43;
}
if ( iEnd44 < iBestEnd )
{
iBestMethod = DCM_CHANGE_END;
iBestEnd = iEnd44;
pbtBest = abtBuff44;
}
*( m_pbtCurr++ ) = iBestMethod;
memcpy( m_pbtCurr, pbtBest, iBestEnd );
m_pbtCurr += iBestEnd;
}
void CDcm::EncodeRec41( BYTE* pbtDest, int* piDestLen, BYTE* pbtSrc, BYTE* pbtSrcOld, int iSrcLen )
{
BYTE* pbtS = pbtSrc + iSrcLen - 1;
pbtSrcOld += iSrcLen - 1;
BYTE* pbtD = pbtDest;
for( int i = 0; i < iSrcLen; i++ )
{
if ( *( pbtS-- ) != * ( pbtSrcOld-- ) )
break;
}
pbtS++;
*( pbtD++ ) = pbtS - pbtSrc;
int iBytes = pbtS - pbtSrc + 1;
while( iBytes-- )
{
*( pbtD++ ) = *( pbtS-- );
}
*piDestLen = pbtD - pbtDest;
}
void CDcm::EncodeRec43( BYTE* pbtDest, int* piDestLen, BYTE* pbtSrc, int iSrcLen )
{
BYTE* pbtEnd = pbtSrc + iSrcLen;
BYTE* pbtCur = pbtSrc;
BYTE* pbtD = pbtDest;
while( pbtCur < pbtEnd )
{
BOOL bFound = FALSE;
for( BYTE* pbtNow = pbtCur; pbtNow < ( pbtEnd - 2 ); pbtNow++ )
{
if ( ( *pbtNow == *(pbtNow+1) ) && ( *pbtNow == *(pbtNow+2) ) )
{
int iUnc = pbtNow - pbtCur;
*( pbtD ++ ) = pbtNow - pbtSrc;
if ( iUnc )
{
memcpy( pbtD, pbtCur, iUnc );
pbtD += iUnc;
}
BYTE bt = *pbtNow;
BYTE*p;
for( p = pbtNow + 1; p < pbtEnd; p++ )
{
if ( *p != bt )
break;
}
if ( p > pbtEnd )
p = pbtEnd;
*( pbtD++ ) = p - pbtSrc;
*( pbtD++ ) = bt;
pbtCur = p;
bFound = TRUE;
break;
}
}
if ( ( pbtCur >= pbtEnd - 2 ) || !bFound )
{
if ( pbtCur < pbtEnd )
{
*( pbtD++ ) = iSrcLen;
memcpy( pbtD, pbtCur, pbtEnd - pbtCur );
pbtD += pbtEnd - pbtCur;
}
break;
}
}
*piDestLen = pbtD - pbtDest;
}
void CDcm::EncodeRec44( BYTE* pbtDest, int* piDestLen, BYTE* pbtSrc, BYTE* pbtSrcOld, int iSrcLen )
{
BYTE* pbtS = pbtSrc;
BYTE* pbtEnd = pbtSrc + iSrcLen;
BYTE* pbtD = pbtDest;
for( int i = 0; i < iSrcLen; i++ )
{
if ( *( pbtS++ ) != * ( pbtSrcOld++ ) )
break;
}
pbtS--;
*( pbtD++ ) = pbtS - pbtSrc;
memcpy( pbtD, pbtS, pbtEnd - pbtS );
pbtD += pbtEnd - pbtS;
*piDestLen = pbtD - pbtDest;
}
#endif __CDISK_WRITE__